﻿namespace Modbus.Data
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Linq;

    using Utility;

    /// <summary>
    /// 事件参数用于在数据存储上执行的读写操作。
    /// </summary>
    public class DataStoreEventArgs : EventArgs
    {
        /// <summary>
        /// 初始化数据存储事件参数实例。
        /// </summary>
        /// <param name="startAddress">数据起始地址</param>
        /// <param name="modbusDataType">数据类型</param>
        private DataStoreEventArgs(ushort startAddress, ModbusDataType modbusDataType)
        {
            this.StartAddress = startAddress;
            this.ModbusDataType = modbusDataType;
        }

        /// <summary>
        ///   获取、设置modbus数据类型
        /// </summary>
        public ModbusDataType ModbusDataType { get; private set; }

        /// <summary>
        /// 数据起始地址。
        /// </summary>
        public ushort StartAddress { get; private set; }

        /// <summary>
        /// 读取或写入的数据。
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures")]
        public DiscriminatedUnion<ReadOnlyCollection<bool>, ReadOnlyCollection<ushort>> Data { get; private set; }

        /// <summary>
        /// 创建多参数数据存储事件参数。
        /// </summary>
        /// <typeparam name="T">数据类型泛型</typeparam>
        /// <param name="startAddress">数据起始地址</param>
        /// <param name="modbusDataType">modbus数据类型</param>
        /// <param name="data">数据</param>
        /// <returns>数据存储事件实例</returns>
        internal static DataStoreEventArgs CreateDataStoreEventArgs<T>(ushort startAddress,
            ModbusDataType modbusDataType, IEnumerable<T> data)
        {
            if (data == null)
                throw new ArgumentNullException("data");

            DataStoreEventArgs eventArgs;

            if (typeof (T) == typeof (bool))
            {
                var a = new ReadOnlyCollection<bool>(data.Cast<bool>().ToArray());
                eventArgs = new DataStoreEventArgs(startAddress, modbusDataType)
                {
                    Data = DiscriminatedUnion<ReadOnlyCollection<bool>, ReadOnlyCollection<ushort>>.CreateA(a)
                };
            }
            else if (typeof(T) == typeof(ushort))
            {
                var b = new ReadOnlyCollection<ushort>(data.Cast<ushort>().ToArray());
                eventArgs = new DataStoreEventArgs(startAddress, modbusDataType)
                {
                    Data = DiscriminatedUnion<ReadOnlyCollection<bool>, ReadOnlyCollection<ushort>>.CreateB(b)
                };
            }
            else
            {
                throw new ArgumentException("Generic type T should be of type bool or ushort");
            }

            return eventArgs;
        }
    }
}
